#ifndef __LOG_HPP__

#define __LOG_HPP__

#include <time.h>
#include "Mutex.hpp"
#include <string>
#include <iostream>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <sys/types.h>

namespace LogSpace
{
    Mutex scapelock;

    class LogStrate
    {
        public:
            virtual void Print(const std::string& message) = 0;
            ~LogStrate() = default;
    };

    // 自动清行。
    const std::string Line = "\r\n";

    // 向显示器打印日志信息。
    class DisplayLog : public LogStrate
    {
        public:
            void Print(const std::string& message) override
            {
                // 加锁在打印
                Lock_Manager lock_manager(scapelock);
                std::cout << message << Line;
            }
        private:
            ;
    };

    // 在指定工作路径创建默认文件。
    const std::string path = "./log";
    const std::string file = "mylog";

    // 向文件中打印日志信息。
    class LogFile : public LogStrate
    {
        public:
            LogFile(const std::string& pathname = path,const std::string& workfile = file)
                :_path(pathname)
                ,_file(workfile)
            {
                Lock_Manager lockmanage(scapelock);

                // 已经存在该文件夹。
                if(std::filesystem::exists(_path))
                {
                    return ;
                }

                try
                {
                    // 没有该文件夹。
                    std::filesystem::create_directories(_path);
                }
                catch(const std::filesystem::filesystem_error &e)
                { 
                    std::cout << e.what() << std::endl;
                }
            }
            // 可以尝试打开文件查看该文件是否存在。
            // 在C++中我们直接用对应的库函数、封装调用就行了。
            void Open_File(const std::string& message)
            {
                ;
            }
            void Print(const std::string& message) override
            {
                _filename = _path + (path.back() == '/' ? "" : "/") + file;

                // 打开文件的类。
                std::ofstream out(_filename,std::ios::app);

                if(!out.is_open())
                {
                    return ;
                }
                else
                {
                    out << message << Line;
                }

                out.close();
            }
        private:
            std::string _filename;
            std::string _path;
            std::string _file;
    };

    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    std::string LogSwitch(const LogLevel& level)
    {
        switch (level)
        {
            case LogLevel::DEBUG : return "DEBUG";
            case LogLevel::INFO : return "INFO";
            case LogLevel::WARNING : return "WARNING";
            case LogLevel::ERROR : return "ERROR";
            case LogLevel::FATAL : return "FATAL";
            default: return "Switch Fail";
        }
    }

    std::string PrintTime()
    {
        time_t current;
        current = time(nullptr);

        struct tm timer;

        localtime_r(&current,&timer);

        char timebuffer[64];

        // %4d年-%02d月-%02d日-星期几-%02d时-%02d分-%02d秒
        snprintf(timebuffer,sizeof(timebuffer),"%4d-%02d-%02d-%02d-%02d-%02d",
            timer.tm_year + 1900,
            timer.tm_mon + 1,
            timer.tm_mday + 1,
            timer.tm_wday,
            timer.tm_hour,
            timer.tm_min
            );

        return timebuffer;
    }

    // 查一下LogMessage为什么会析构两次:
    int LoggerNum;
    int LogMessageNum;

    class Logger
    {
        public:
            void EnableDisplayLog()
            {
                _fflush_strategy = std::make_unique<DisplayLog>();
            }
            void EnableLogFile()
            {
                _fflush_strategy = std::make_unique<LogFile>();;
            }
            Logger()
            {
                EnableDisplayLog();
            }
            class LogMessage
            {
                public:
                    LogMessage(const LogLevel& level,const std::string src_name,int line_number,Logger& log)
                        :_curr_time(PrintTime())
                        ,_level(level)
                        ,_pid(getpid())
                        ,_src_name(src_name)
                        ,_logger(log)
                    {
                        std::stringstream ss;
                        ss << "[" << _curr_time << "]";
                        ss << "[" << LogSwitch(_level) << "]";
                        ss << "[" << _pid << "]";
                        ss << "[" << _src_name << "]";
                        ss << "[" << _line_number << "]";
                        ss << "-";
                        _loginfo = ss.str();
                    }
                    template < class T >
                    // 为什么会析构两次，这里返回值为LogMessage拷贝过来的。
                    LogMessage& operator << (const T& message)
                    {
                        std::stringstream ss;
                        ss << message;
                        _loginfo += ss.str();

                        return (*this);
                    }
                    void Print()
                    {
                        _logger._fflush_strategy->Print(_loginfo);
                    }
                    ~LogMessage()
                    {
                        Print();
                        // ++LogMessageNum;
                        // std::cout << "LogMessageNum:" << LogMessageNum << std::endl;
                    }
                private:
                    std::string _curr_time;
                    LogLevel _level;
                    pid_t _pid;
                    std::string _src_name;
                    int _line_number;
                    std::string _loginfo; // 合并之后，一条完整的信息
                    Logger& _logger;
            };

            LogMessage operator()(LogLevel level, std::string name, int line)
            {
                return LogMessage(level, name, line, *this);
            }

            ~Logger()
            {
                // ++LoggerNum;
                // std::cout << "LoggerNum:" << LoggerNum << std::endl;
            }
        private:
            // 虚函数，没有选项。
            std::unique_ptr<LogStrate> _fflush_strategy;
    };

    // 方便从外部调用LogMessage。
    Logger log;

    // __FILE__、__LINE__当前文件名，当前行号。
    #define LOG(level) log(level, __FILE__, __LINE__)
    #define Enable_Console_Log_Strategy() log.EnableConsoleLogStrategy()
    #define Enable_File_Log_Strategy() log.EnableFileLogStrategy()
}

    

#endif 